package com.example.demo.thread.current;

import com.example.demo.util.UnsafeInstance;
import sun.misc.Unsafe;

import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.LockSupport;

/**
 * 公平锁
 *
 * @author Code Farmer
 * @date 2020/5/28 22:47
 */
public class AqsLock {

    /**
     * 当前加锁状态，记录加锁的次数
     */
    private volatile int state = 0;

    /**
     * 当前持有锁的线程
     */
    private Thread lockHolder;

    private ConcurrentLinkedQueue<Thread> waiters = new ConcurrentLinkedQueue<>();//基于CAS保证入队出队安全

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public Thread getLockHolder() {
        return lockHolder;
    }

    public void setLockHolder(Thread lockHolder) {
        this.lockHolder = lockHolder;
    }

    /**
     * 尝试获取锁
     *
     * @return
     */
    private boolean acquire() {
        Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {//同步器还没有加锁
//            if (waiters.size() == 0 || compareAndSwapInt(0, 1)) { //
            if ((waiters.size() == 0 || current == waiters.peek()) && compareAndSwapInt(0, 1)) {
                this.setLockHolder(current);
                return true;
            }
        }
        return false;
    }

    /**
     * 加锁
     */
    public void lock() {
        if (acquire()) {//加锁成功
            return;
        } else {
            Thread current = Thread.currentThread();
            waiters.add(current);//保存对线程的引用
            for (; ; ) {
                //让出cpu使用权
                //Thread.yield();//会持续浪费CPU
                //Thread.sleep(1000)  //为什么不使用sleep？虽然使用sleep会减少cpu的使用，但是1000ms时间可能会发生这样事情，200ms的时候可能上一个线程释放锁，然后其他线程要阻塞800ms，如果是一个用户业务，那个用户体验会非常差
                //Thread.sleep(1); //1ms会造成频繁切换上下文而造成cpu浪费
                if ((current == waiters.peek()) && acquire()) {
                    waiters.poll();//唤醒后，把自身从队列中移出
                    return;
                }
                //阻塞当前线程,释放cpu资源
                LockSupport.park(current);
            }
        }
    }

    /**
     * 解锁
     */
    public void unlock() {
        if (Thread.currentThread() != lockHolder) {
            throw new RuntimeException("lock holder is not current thread");
        }
        int state = getState();
        if (compareAndSwapInt(state, 0)) {
            setLockHolder(null);
            Thread first = waiters.peek();
            if (first != null) {
                LockSupport.unpark(first);//由于唤醒线程是随机唤醒，我们不能保证唤醒的是哪一个线程，所以需要在获取锁时判断是不是等于队列第一个线程
            }
        }
    }

    public final boolean compareAndSwapInt(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

    private static final Unsafe unsafe = UnsafeInstance.reflectGetUnsafe();

    private static long stateOffset;

    /**
     * 计算state变量偏移量
     */
    static {
        try {
            stateOffset = unsafe.objectFieldOffset(AqsLock.class.getDeclaredField("state"));
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }

}
